#pragma once

#include "Socket.h"
#include <functional>
#include <sys/select.h>

namespace zmh
{
    // 服务器一般是不可拷贝的,甚至有些环境下应该是单例模式
    // 服务器只负责获取链接 关闭链接的操作 协议模块负责数据的收发与格式化
    // 对数据的处理---Echo
    class serve : public nocopy
    {
        typedef std::function<void(std::shared_ptr<Socket>)> service;
        static const int fds_size = sizeof(fd_set) * 8; // select能同时检测的fd上限
    public:
        serve(const Intaddr &addr, int backlog = 16)
        {
            _listSocket->GetListenSocket(addr, backlog);
            memset(_fds, 0xFF, sizeof _fds);
            _fds[0] = _listSocket->fd();
        }
        void start()
        {
            _isrunning = true;
            while (_isrunning)
            {
                int maxfd = -1;
                fd_set rfds;
                FD_ZERO(&rfds);

                for (auto x : _fds)
                {
                    if (x == -1)
                        continue;

                    FD_SET(x, &rfds);
                    maxfd = std::max(maxfd, x);
                }

                switch (select(maxfd + 1, &rfds, nullptr, nullptr, nullptr))
                {
                case -1:
                    LOG(zmh::ERROR) << "select error";
                    break;
                case 0:
                    LOG(zmh::INFO) << "timeout ...";
                    break;
                default:
                    Dispatch(rfds);
                }
            }
            _isrunning = false;
        }
        void Accept()
        {
            Intaddr peer;
            int fd = _listSocket->accept(peer);
            if (fd >= 0)
            {
                // 获取到了一个连接，将他写进辅助数组
                for (int i = 0; i < fds_size; i++)
                {
                    if (_fds[i] == -1)
                    {
                        _fds[i] = fd;
                        break;
                    }
                }
            }
        }
        void Echo(int pos, int fd)
        {
            char buffer[1024];
            int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
            if (n == 0)
            {
                // 客户端关闭
                close(fd);
                _fds[pos] = -1;
            }
            else
            {
                buffer[n-1] = 0;
                std::cout << "Client Say: " << buffer << std::endl;
                // std::string s = std::string("Serve Say: ") + buffer + std::to_string('\n');
                // send(fd,s.c_str(),s.size(),0);
            }
        }
        void Dispatch(const fd_set &rfds)
        {
            for (int i = 0; i < fds_size; i++)
            {
                if (_fds[i] == -1)
                    break;
                if (FD_ISSET(_fds[i], &rfds) == 0)
                    continue; // 读事件未就绪
                else
                {
                    if (i == 0)
                    {
                        Accept();
                    }
                    else
                    {
                        Echo(i, _fds[i]);
                    }
                }
            }
        }

    private:
        std::shared_ptr<Socket> _listSocket = std::make_shared<Tcp_Socket>(); // 监听套接字
        bool _isrunning = false;                                              // 服务器的状态 --- true表运行

        int _fds[fds_size]; // 辅助数组 --- 需要被检测的fd
    };
}
